//
//  PongFieldController.mm
//
//  Created by Jonathan Saggau on 2007-08-09.
//  Copyright (c) 2007 __MyCompanyName__. All rights reserved.
//

#import "PongFieldController.h"
#import "PongField.h"
#import "ServerController.h"
#import "ClientController.h"
#import "Common.h"

extern NSRect thumbRect;
extern BOOL pongLeftArrow;
extern BOOL pongRightArrow;

@interface PongFieldController (PrivateAPI)
-(void)startListening;
-(void)connect;
-(void)die;
@end

@implementation PongFieldController

-(id)initWithFieldRect:(NSRect) fieldRect;
{
	self = [super init];
	if (nil != self)
	{
        srandom(time(NULL));
        
		field = [[PongField alloc] initWithFieldRect:fieldRect];
        updating = NO;
        stepX = stepY = 0.0f;
        shouldBounce = NO;
        shouldEndGame = NO;
        
#ifndef NO_NETWORKING
        serverController = [[ServerController alloc] init];
        [self startListening];
        
        clientController = [[ClientController alloc] init];
        [self connect];
#endif
    }
    return self;
}

-(void)dealloc
{
#ifndef NO_NETWORKING
    
    [clientController disconnect];
    [serverController stopListening];
    
    [clientController release]; clientController = nil;
    [serverController release]; serverController = nil;
#endif
    [field release]; field = nil;	
    [super dealloc];
}

-(void)startListening
{
#ifndef NO_NETWORKING
    @try {
        [serverController startListening];
        sleep(2);
    }
    @catch (NSException * err) 
    {
        NSString *fancyAlertDebugging = [NSString stringWithFormat:@"Fancy Debug Info (R):%@", [err reason]];
        int button = NSRunAlertPanel(
                                     [NSString stringWithFormat:@"I'm having Trouble listening for network messages"],
                                     fancyAlertDebugging,
                                     @"Try Again",
                                     nil,
                                     @"Cancel");
        
        switch (button) 
        {
            case NSAlertDefaultReturn:
                NSLog(@"Default Return");
                [self startListening];
                break;
            case NSAlertAlternateReturn:
                NSLog(@"Alternate Return");
                break;
            case NSAlertOtherReturn:
                NSLog(@"Other Return");
                [self die];
                break;
            case NSAlertErrorReturn:
                NSLog(@"Error Return");
                break;
            default:
                break;
        }
    }
#endif
}

-(void)connect
{
#ifndef NO_NETWORKING
    @try 
    {
        [clientController connect];
    }
    @catch (NSException * err)
    {
        NSString *fancyAlertDebugging = [NSString stringWithFormat:@"Fancy Debug Info (R):%@", [err reason]];
        int button = NSRunAlertPanel(
                                     [NSString stringWithFormat:@"I'm having Trouble sending network messages"],
                                     fancyAlertDebugging,
                                     @"Try Again",
                                     nil,
                                     @"Cancel");
        
        switch (button) 
        {
            case NSAlertDefaultReturn:
                NSLog(@"Default Return");
                [self connect];
                break;
            case NSAlertAlternateReturn:
                NSLog(@"Alternate Return");
                [self die];
                break;
            case NSAlertOtherReturn:
                NSLog(@"Other Return");
                [self die];
                break;
            case NSAlertErrorReturn:
                NSLog(@"Error Return");
                [self die];
                break;
            default:
                break;
        }
    }
#endif
}

-(void)die
{
    [clientController disconnect];
    [serverController stopListening];
    
    if(delegate && [delegate respondsToSelector:@selector(crashAndBurn)])
        [delegate performSelector:@selector(crashAndBurn)];
    else
        exit(1);
}

-(void)beginNewGame
{
    //LogMethod();
    NSRect fieldRect = [field fieldRect];
    NSRect ballRect;
    ballRect.size = NSMakeSize(10.0, 10.0);
    ballRect.origin.x = (fieldRect.size.height * 0.5) - (ballRect.size.height * 0.5);
    ballRect.origin.y = (fieldRect.size.width * 0.5) - (ballRect.size.width * 0.5);
    [field setBallRect:ballRect];
    
    stepX = ((float) ((random() % 100) + 50) * 0.01) * MOVEMENT_MULTIPLIER;
    stepY = MOVEMENT_MULTIPLIER;
    updating = YES;
}

-(void) bounce
{
    //LogMethod();
    shouldBounce = YES;
}

-(void)endGame
{
    //LogMethod();
    shouldEndGame = YES;
    if(nil != delegate && [delegate respondsToSelector:@selector(gameDidEnd)])
        [delegate performSelector:@selector(gameDidEnd)];
}

-(void)updatePhysics
{
    //Here is where we move stuff.
    if (!updating)
        return;
    NSRect ballRect = [[self field] ballRect];
    NSRect fieldRect = [[self field] fieldRect];
    NSRect leftPaddle = [[self field] leftPaddle];
    NSRect rightPaddle = [[self field] rightPaddle];
    float maxX = fieldRect.origin.x + fieldRect.size.width - ballRect.size.width;
    float maxY = fieldRect.origin.y + fieldRect.size.height - ballRect.size.height;
    float minX = fieldRect.origin.x;
    float minY = fieldRect.origin.y;
    
    ballRect.origin.y += stepY;
    ballRect.origin.x += stepX;
    if(NSIntersectsRect(ballRect, leftPaddle) || NSIntersectsRect(ballRect,rightPaddle))
    {
        stepY *= -1; // switchDirection
        [self bounce];
    }
    if(ballRect.origin.x >= maxX || ballRect.origin.x <= minX)
    {
        stepX *= -1; // switchDirection
        [self bounce];
    }
    if (ballRect.origin.y >= maxY + ballRect.size.height)
    {
        updating = NO;
        int rightScore = [[self field] rightScore];
        [[self field] setRightScore:rightScore + 1];
        [self endGame];
        return;
    }
    if (ballRect.origin.y <= minY - ballRect.size.height)
    {
        updating = NO;
        int leftScore = [[self field] leftScore];
        [[self field] setLeftScore:leftScore + 1];
        [self endGame];
        return;
    }
    
    [[self field] setBallRect:ballRect];
}



-(void)updateUserInteraction
{
    NSRect leftPaddleRect = [field leftPaddle];
    NSRect fieldRect = [[self field] fieldRect];
    if (pongRightArrow)
        leftPaddleRect.origin.x += PADDLE_STEP * MOVEMENT_MULTIPLIER;
    if (pongLeftArrow)
        leftPaddleRect.origin.x -= PADDLE_STEP * MOVEMENT_MULTIPLIER;
    
    //don't move if we're going off the screen
    if ((leftPaddleRect.origin.x < 0.0) || 
        ((leftPaddleRect.origin.x + leftPaddleRect.size.width) > (fieldRect.origin.x + fieldRect.size.width)))
        return;
    
    [field setLeftPaddle:leftPaddleRect];
}

#ifndef NO_NETWORKING

-(void)updateAndSendClientMsg
{
    NSString *bigMessage;
    
    NSRect aRect = [field leftPaddle];
    NSString *leftPaddle = NSStringFromRect(aRect);
    
    aRect = [field ballRect];
    NSString *ball = NSStringFromRect(aRect);
    //dummy msg
    NSString *bounce = (shouldBounce) ? @"BB;BB" : @"DU;MY";
    NSString *ender = (shouldEndGame) ? @"EG;EG" : @"DU;MY";
    
    shouldEndGame = NO;
    shouldBounce = NO;
    bigMessage = [NSString stringWithFormat:@"%@;%@;PB;%@;LP;%@%@", bounce, ender, ball, leftPaddle, PACKET_TAG];
    NSLog(@"big message = %@", bigMessage);
    
    [clientController send:bigMessage];
}

- (void)updateInfoFromServer
{
    NSString *incomingMsg = [serverController messageReceived];
    
    if (IsEmpty(incomingMsg))
        return;
    
    NSArray *indivMsgs = [incomingMsg componentsSeparatedByString:@";"];
    NSString *eachMsg;
    NSString *eachMsgNext;
    NSRect aRect;
    int i;
    for (i = 0; i< [indivMsgs count]; i+=2)
    {
        eachMsg = [indivMsgs objectAtIndex:i];
        eachMsgNext = [indivMsgs objectAtIndex:i+1];
        if([eachMsg isEqualToString:@"RP"])
        {
            aRect = NSRectFromString(eachMsgNext);
            [field setRightPaddle:aRect];
        }
    }
}
#endif

-(void)update
{
    [[self field] setRightFinger:thumbRect.origin];
    [self updateUserInteraction];
    [self updatePhysics];
    
#ifndef NO_NETWORKING
    [self updateAndSendClientMsg];
    [self updateInfoFromServer];
#endif
}

-(PongField *)field;
{
    return field;
}

- (id)delegate
{
    return delegate; 
}
- (void)setDelegate:(id)aDelegate
{
    if (delegate != aDelegate) {
        [aDelegate retain];
        [delegate release];
        delegate = aDelegate;
    }
}



@end
